home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 026-050 / scopedisk48 / easymenu / menu.c < prev    next >
C/C++ Source or Header  |  1995-03-18  |  10KB  |  339 lines

  1. /* easy menus: Copyright 1987 Peter da Silva, all rights reserved.
  2.  *
  3.  *     Permission is granted to use this in any application, so long as
  4.  *     this notice is retained in the source. Permission is granted to
  5.  *     modify the code as you like, so long as this notice (between the
  6.  *     first line beginning "easy menus" and the end of this paragraph,
  7.  *     inclusive) is retained intact.
  8.  *
  9.  * Usage:
  10.  *
  11.  *     #include "menu.h"
  12.  *
  13.  *     struct MenuPtr menudata;
  14.  *     struct MenuPtr *menuptr = &menudata;
  15.  *
  16.  *     init_menus(menuptr);    / * Just zero menu pointer out * /
  17.  *
  18.  *     for(each menu item) {
  19.  *             add_menu(menuptr, menu, item, subitem, flags);
  20.  *     }
  21.  *
  22.  *  Flags:
  23.  *    SUBITEM_NOCHECK  -- subitem does not require a checkmark.
  24.  *    SUBITEM_SELECTOR -- subitem is a 1 of n selector, use mutual-exclude.
  25.  *    SUBITEM_TOGGLE   -- subitem is a toggled flag.
  26.  *    SUBITEM_SELECTED -- defaults to checked.
  27.  *
  28.  *
  29.  *     SetMenuStrip(yourwindow, menuptr->MenuBar);
  30.  *
  31.  *     ...
  32.  *
  33.  *     ClearMenuStrip(yourwindow);
  34.  *
  35.  *     trash_menus(menuptr);
  36.  *
  37.  * Notes:
  38.  *
  39.  *     if you don't want any subitems, use zero for the subitem value.
  40.  *
  41.  *     subitem is always initialised as a CHECKIT item with all the other
  42.  *     subitems mutually excluded.
  43.  *
  44.  *     it is intended that the menu be set up with all action items in
  45.  *     the first level of the menu, and all toggles in the second level...
  46.  *     this is a piece of blatant authoritarianism on my part. I've seen
  47.  *     too many menus with no rhyme or reason. Look at AmigaTerm (the term
  48.  *     program that comes with the Amiga modem) some time. Baud rate has
  49.  *     an item all by itself, but word size is hidden off in a menu with
  50.  *     things like bell sound.
  51.  *
  52.  *     the appearance of the menus produced by this is (in my humble
  53.  *     opinion) good. I took some care making text centered in menu boxes,
  54.  *     for example.
  55.  */
  56. #include <exec/memory.h>
  57. #include <intuition/intuition.h>
  58. #include "menu.h"
  59. #include "fonts.h"
  60.  
  61. /*
  62. struct MenuPtr {
  63.        struct Menu *MenuBar;
  64.        struct Remember *MenuMemory;
  65. };
  66. */
  67.  
  68. char *AllocRemember();
  69.  
  70. static struct Menu *new_menu();
  71. static struct MenuItem *new_item(), *new_subitem();
  72.  
  73. #define TOMENUNUM(i,j,k) (SHIFTMENU(i)|SHIFTITEM(j)|SHIFTSUB(k))
  74. #define TextLen(s) (strlen(s)*FONTWIDTH)
  75.  
  76. trash_menus(menuptr)
  77. struct MenuPtr *menuptr;
  78. {
  79.        FreeRemember(&menuptr->MenuMemory, 1);
  80.        menuptr->MenuMemory = 0;
  81.        menuptr->MenuBar = 0;
  82. }
  83.  
  84. init_menus(menuptr)
  85. struct MenuPtr *menuptr;
  86. {
  87.        menuptr->MenuMemory = 0;
  88.        menuptr->MenuBar = 0;
  89. }
  90.  
  91. int add_menu(menuptr, menuname, itemname, subitemname, flags)
  92. struct MenuPtr *menuptr;
  93. char *menuname, *itemname, *subitemname;
  94. long flags;
  95. {
  96.        int i, j, k;
  97.        struct Menu *menu;
  98.        struct MenuItem *item;
  99.        struct MenuItem *subitem;
  100.  
  101.        if(menuptr->MenuBar) {
  102.                for(i = 0, menu = menuptr->MenuBar;
  103.                    menu;
  104.                        menu = menu->NextMenu, i++
  105.                   )
  106.                        if(strcmp(menuname, menu->MenuName)==0)
  107.                                break;
  108.                if(!menu)
  109.                        menu = new_menu(menuptr, menuname);
  110.                if(!menu)
  111.                        return MENUNULL;
  112.        } else {
  113.                i = 0;
  114.                menu = new_menu(menuptr, menuname);
  115.                if(!menu)
  116.                        return MENUNULL;
  117.        }
  118.        for(j = 0, item = menu->FirstItem;
  119.                item;
  120.                item = item->NextItem, j++
  121.           ) {
  122.                struct IntuiText *text;
  123.                text = (struct IntuiText *)item->ItemFill;
  124.                if(strcmp(itemname, text->IText) == 0)
  125.                        break;
  126.        }
  127.        if(subitemname) {
  128.                if(!item)
  129.                        item = new_item(menuptr, menu, itemname);
  130.                if(!item)
  131.                        return MENUNULL;
  132.                for(k = 0, subitem = item->SubItem;
  133.                        subitem;
  134.                        subitem = subitem->NextItem, k++
  135.                   ) {
  136.                        struct IntuiText *text;
  137.                        text = (struct IntuiText *)subitem->ItemFill;
  138.                        if(strcmp(subitemname, text->IText) == 0)
  139.                                break;
  140.                }
  141.                if(!subitem)
  142.                        subitem = new_subitem(menuptr, item, subitemname, flags);
  143.                if(!subitem)
  144.                        return MENUNULL;
  145.                return TOMENUNUM(i, j, k);
  146.        } else {
  147.                if(!item)
  148.                        item = new_item(menuptr, menu, itemname);
  149.                if(!item)
  150.                        return MENUNULL;
  151.                return TOMENUNUM(i, j, NOSUB);
  152.        }
  153. }
  154.  
  155. static struct Menu *
  156. new_menu(menuptr, name)
  157. struct MenuPtr *menuptr;
  158. char *name;
  159. {
  160.        struct Menu *menu;
  161.  
  162.        menu = (struct Menu *)AllocRemember(
  163.                &menuptr->MenuMemory,
  164.                sizeof(struct Menu),
  165.                MEMF_PUBLIC);
  166.        if(!menu)
  167.                return 0;
  168.        menu->NextMenu = NULL;
  169.        menu->LeftEdge = 0;
  170.        menu->TopEdge = 0;
  171.        menu->Width = TextLen(name)+FONTWIDTH;
  172.        menu->Height = 0;
  173.        menu->Flags = MENUENABLED;
  174.        menu->MenuName = name;
  175.        menu->FirstItem = 0;
  176.        if(menuptr->MenuBar) {
  177.                struct Menu *ptr, *prev;
  178.                for(ptr = menuptr->MenuBar; ptr; ptr=ptr->NextMenu) {
  179.                        menu->LeftEdge += ptr->Width;
  180.                        prev = ptr;
  181.                }
  182.                prev->NextMenu = menu;
  183.        } else {
  184.                menuptr->MenuBar = menu;
  185.        }
  186.  
  187.        return menu;
  188. }
  189.  
  190. static struct item *
  191. new_item(menuptr, menu, name)
  192. struct MenuPtr *menuptr;
  193. char *name;
  194. struct Menu *menu;
  195. {
  196.        struct MenuItem *item;
  197.        struct IntuiText *text;
  198.  
  199.        item = (struct MenuItem *)AllocRemember(
  200.                &menuptr->MenuMemory,
  201.                sizeof(struct MenuItem),
  202.                MEMF_PUBLIC);
  203.        if(!item)
  204.                return 0;
  205.        text = (struct IntuiText *)AllocRemember(
  206.                &menuptr->MenuMemory,
  207.                sizeof(struct IntuiText),
  208.                MEMF_PUBLIC);
  209.        if(!text)
  210.                return 0;
  211.  
  212.        text->FrontPen = AUTOFRONTPEN;
  213.        text->BackPen = AUTOBACKPEN;
  214.        text->DrawMode = JAM2;
  215.        text->LeftEdge = 1;
  216.        text->TopEdge = 1;
  217.        text->ITextFont = NULL;
  218.        text->IText = name;
  219.        text->NextText = NULL;
  220.  
  221.        item->NextItem = NULL;
  222.        item->LeftEdge = 0;
  223.        item->TopEdge = 0;
  224.        item->Width = IntuiTextLength(text)+2;
  225.        if(item->Width <= menu->Width)
  226.                item->Width = menu->Width+1;
  227.        item->Height = FONTHEIGHT+1;
  228.        item->Flags = ITEMTEXT|HIGHCOMP|ITEMENABLED;
  229.        item->MutualExclude = 0;
  230.        item->ItemFill = text;
  231.        item->SelectFill = NULL;
  232.        item->Command = 0;
  233.        item->SubItem = NULL;
  234.        item->NextSelect = NULL;
  235.  
  236.        if(menu->FirstItem) {
  237.                struct MenuItem *ptr, *prev;
  238.                for(ptr = menu->FirstItem; ptr; ptr=ptr->NextItem) {
  239.                        if(item->Width > ptr->Width) {
  240.                                if(ptr->SubItem)
  241.                                        nudge(ptr->SubItem, item->Width-ptr->Width);
  242.                                ptr->Width = item->Width;
  243.                        } else if(ptr->Width>item->Width)
  244.                                item->Width = ptr->Width;
  245.                        prev = ptr;
  246.                }
  247.                item->TopEdge = prev->TopEdge + prev->Height;
  248.                prev->NextItem = item;
  249.        } else {
  250.                menu->FirstItem = item;
  251.        }i}
  252.  
  253.        return item;
  254. }
  255.  
  256. static nudge(item, delta)
  257. struct MenuItem *item;
  258. int delta;
  259. {
  260.        while(item) {
  261.                item->LeftEdge += delta;
  262.                item = item->NextItem;
  263.        }
  264. }
  265.  
  266. static struct item *
  267. new_subitem(menuptr, item, name, flags)
  268. struct MenuPtr *menuptr;
  269. char *name;
  270. struct MenuItem *item;
  271. long flags;
  272. {
  273.        struct MenuItem *subitem;
  274.        struct IntuiText *text;
  275.  
  276.        subitem = (struct MenuItem *)AllocRemember(
  277.                &menuptr->MenuMemory,
  278.                sizeof(struct MenuItem),
  279.                MEMF_PUBLIC);
  280.        if(!subitem)
  281.                return 0;
  282.        text = (struct IntuiText *)AllocRemember(
  283.                &menuptr->MenuMemory,
  284.                sizeof(struct IntuiText),
  285.                MEMF_PUBLIC);
  286.        if(!text)
  287.                return 0;
  288.  
  289.        text->FrontPen = AUTOFRONTPEN;
  290.        text->BackPen = AUTOBACKPEN;
  291.        text->DrawMode = JAM2;
  292.        text->LeftEdge = CHECKWIDTH+1;
  293.        text->TopEdge = 1;
  294.        text->ITextFont = NULL;
  295.        text->IText = name;
  296.        text->NextText = NULL;
  297.  
  298.        subitem->NextItem = NULL;
  299.        subitem->LeftEdge = item->Width;
  300.        subitem->TopEdge = 0;
  301.        subitem->Width = IntuiTextLength(text)+2;
  302.        if(flags != SUBITEM_NOCHECK) subitem->Width += CHECKWIDTH;
  303.        subitem->Height = FONTHEIGHT+1;
  304.        subitem->Flags = ITEMTEXT|ITEMENABLED|HIGHCOMP;
  305.        subitem->MutualExclude = 0;
  306.        if(flags != SUBITEM_NOCHECK) {
  307.                subitem->Flags |= CHECKIT;
  308.                if(flags & SUBITEM_TOGGLE) subitem->Flags |= MENUTOGGLE;
  309.                if(flags & SUBITEM_SELECTED) subitem->Flags |= CHECKED;
  310.        }
  311.        subitem->ItemFill = text;
  312.        subitem->SelectFill = NULL;
  313.        subitem->Command = 0;
  314.        subitem->SubItem = NULL;
  315.        subitem->NextSelect = NULL;
  316.  
  317.        if(item->SubItem) {
  318.                struct MenuItem *ptr, *prev;
  319.                int i;
  320.                for(i=0, ptr = item->SubItem; ptr; i++, ptr=ptr->NextItem) {
  321.                        if(subitem->Width > ptr->Width)
  322.                                ptr->Width = subitem->Width;
  323.                        else if(ptr->Width>subitem->Width)
  324.                                subitem->Width = ptr->Width;
  325.                        prev = ptr;
  326.                }
  327.                subitem->TopEdge = prev->TopEdge + prev->Height;
  328.                if(flags & SUBITEM_SELECTOR)
  329.                        subitem->MutualExclude = ~(1<<i);
  330.                prev->NextItem = subitem;
  331.        } else {
  332.                item->SubItem = subitem;
  333.                if(flags & SUBITEM_SELECTOR)
  334.                        subitem->MutualExclude = ~1;
  335.        }
  336.  
  337.        return subitem;
  338. }
  339.